package org.common.utils.config.handler;

import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import org.common.utils.config.ConfigException;
import org.common.utils.config.ConfigInfo;
import org.common.utils.config.ConfigObject;
import org.common.utils.config.ConfigType;
import org.common.utils.nacos.NacosTool;
import org.common.utils.nacos.entity.NacosAddress;
import org.common.utils.nacos.entity.NacosConfigAddress;
import org.common.utils.tool.CollectionTool;
import org.common.utils.tool.CommonTool;
import org.common.utils.tool.StringTool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Executor;

/**
 * nacos配置处理器
 * @author zhouzhibing
 * @date 2025/7/29
 */
public class NacosHandler extends AbstractConfigHandler {

    private static final Logger log = LoggerFactory.getLogger(NacosHandler.class);

    /**
     * nacos配置服务列表
     */
    private List<ConfigServiceInfo> configServiceInfoList;

    public NacosHandler() {
        super(ConfigType.NACOS);
    }

    @Override
    protected boolean loadImpl(ConfigObject configObject , ConfigInfo configInfo , Map<String , String> configMap) {
        List<NacosConfigAddress> nacosConfigAddressList = configInfo.getNacosConfigAddress();
        if(CollectionTool.isEmpty(nacosConfigAddressList)) {
            log.warn("NacosHandler.loadImpl : nacosAddressList is null , ignore load .");
            return false;
        }

        if(CollectionTool.isEmpty(configServiceInfoList)) {
            configServiceInfoList = initConfigService(configObject , nacosConfigAddressList);
        }

        for (ConfigServiceInfo configServiceInfo : configServiceInfoList) {
            String dataId = configServiceInfo.dataId;
            String group = configServiceInfo.group;
            ConfigService configService = configServiceInfo.configService;
            NacosConfigAddress configAddress = configServiceInfo.configAddress;
            String configContent = null;
            try {
                configContent = configService.getConfig(dataId, group, CommonTool.DEFAULT_TIME_OUT_MILLISECONDS);
                if(configContent == null) {
                    ConfigException e = new ConfigException("NacosHandler.loadImpl : configContent is null , configContent == null , dataId = " + dataId + " , group = " + group + " , configAddress = " + configAddress);
                    log.error("" , e);
                    throw e;
                }

                Properties properties = new Properties();
                properties.load(new StringReader(configContent));
                properties.forEach((key , value) -> configMap.put(key.toString() , value.toString()));
                log.info("NacosHandler.loadImpl success , dataId = {} , group = {} , configContent = {} ", dataId , group , configContent);
            } catch (Exception e) {
                log.error("NacosHandler.loadImpl error , configAddress = {} , dataId = {} , group = {}" , configAddress , dataId , group , e);
                throw new ConfigException(e);
            }
        }

        return true;
    }

    /**
     * 初始化nacos配置服务
     * @param configObject 配置对象
     * @param nacosConfigAddressList nacos配置地址列表
     * @return nacos配置服务列表
     */
    private List<ConfigServiceInfo> initConfigService(ConfigObject configObject , List<NacosConfigAddress> nacosConfigAddressList) {
        List<ConfigServiceInfo> configServiceInfoList = new ArrayList<>(nacosConfigAddressList.size());
        for (NacosConfigAddress configAddress : nacosConfigAddressList) {
            if(configAddress == null) {
                ConfigException e = new ConfigException("NacosHandler.initConfigService : configAddress is null");
                log.error("" , e);
                throw e;
            }

            String dataId = configAddress.getDataId();
            String group = configAddress.getGroup();
            if (StringTool.isEmpty(dataId)) {
                ConfigException e = new ConfigException("NacosHandler.initConfigService : dataId is null");
                log.error("" , e);
                throw e;
            }

            if (StringTool.isEmpty(group)) {
                ConfigException e = new ConfigException("NacosHandler.initConfigService : group is null");
                log.error("" , e);
                throw e;
            }

            NacosAddress nacosAddress = configAddress.getNacosAddress();
            ConfigService configService = NacosTool.createConfigService(nacosAddress);
            Listener listener = createListener(configObject);
            try {
                configService.addListener(dataId, group, listener);
            } catch (NacosException e) {
                log.error("NacosHandler.initConfigService error , configAddress = {} , dataId = {} , group = {}" , configAddress , dataId , group , e);
                throw new ConfigException(e);
            }
            log.info("NacosHandler.initConfigService success , configAddress = {} , dataId = {} , group = {}" , configAddress , dataId , group);
            configServiceInfoList.add(new ConfigServiceInfo(dataId , group , configAddress , configService , listener));
        }
        return configServiceInfoList;
    }

    /**
     * 创建监听器
     * @param configObject 配置对象
     * @return 监听器
     */
    private Listener createListener(ConfigObject configObject) {
        return new Listener() {
            @Override
            public Executor getExecutor() {
                return null;
            }

            @Override
            public void receiveConfigInfo(String configContent) {
                try {
                    configObject.reLoad();
                    log.info("ConfigManager nacos reload , configContent = {} " , configContent);
                } catch (Exception e) {
                    log.error("ConfigManager nacos reload error " , e);
                }
            }
        };
    }

    /**
     * 销毁已经存在所有nacos配置服务
     */
    private void destroyConfigService() {
        if(CollectionTool.isEmpty(configServiceInfoList))
            return;

        for (ConfigServiceInfo listenerInfo : configServiceInfoList) {
            ConfigService configService = listenerInfo.configService;
            NacosConfigAddress configAddress = listenerInfo.configAddress;
            String dataId = configAddress.getDataId();
            String group = configAddress.getGroup();
            Listener listener = listenerInfo.listener;
            try {
                configService.removeListener(dataId , group , listener);
                configService.shutDown();
            } catch (NacosException e) {
                log.error("ConfigManager.destroyConfigService error , configService = {} , configAddress = {} " , configService , configAddress , e);
            }
        }
        configServiceInfoList.clear();
    }

    /**
     * 配置服务信息
     */
    private static class ConfigServiceInfo {
        private String dataId;
        private String group;
        private NacosConfigAddress configAddress;
        private ConfigService configService;
        private Listener listener;

        public ConfigServiceInfo(String dataId , String group , NacosConfigAddress configAddress, ConfigService configService, Listener listener) {
            this.dataId = dataId;
            this.group = group;
            this.configAddress = configAddress;
            this.configService = configService;
            this.listener = listener;
        }
    }

}
